﻿namespace JoinBox.Forms;

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;

#if true2

    // http://www.cadgj.com/?p=297
    // 注册表中 计算机\HKEY_LOCAL_MACHINE\SOFTWARE\Classes\AutoCAD.Application.17 找到对应的GUID
    // 所以这个类可以扔掉了
    public class AcadClsId
    {
        // var acadGuid = AcadClsId.GetAcadGuid("17.1");
        // var bvv = AcadClsId.GetAcadVer("6AB55F46-2523-4701-2222-B226F46252BA");

        // (getvar "acadver")
        public static Dictionary<string, Guid> AcadClsIds = new()
        {
            { "15", new Guid("8E75D911-3D21-11d2-85C4-080009A0C626") },
            { "16", new Guid("1365A45F-0C8F-4806-A26A-6B22AD37EC66") },
            { "16.1", new Guid("FC280999-88C6-4499-9622-3B795A8B4A5F") },
            { "16.2", new Guid("F131FB74-0E12-4533-8091-D71FE9CCD91D") },
            { "17", new Guid("28B7AA99-C0F9-4C47-995E-8A8D729603A1") },
            { "17.1", new Guid("6AB55F46-2523-4701-A912-B226F46252BA") },// 08
            { "17.2", new Guid("2F1F7574-ECCA-4361-B4DE-C411BF7EEE23") },
            { "18", new Guid("6D7AE628-FF41-4CD3-91DD-34825BB1A251") },
            { "18.1", new Guid("C92FB640-AD4D-498A-9979-A51A2540C977") },
            { "18.2", new Guid("B77E471C-FBF3-4CB5-880F-D7528AD4B349") },
            { "19", new Guid("BD0DEB94-63DB-4392-9420-6EEE05094B1F") },
            { "19.1", new Guid("7DE1BE5C-CEBA-4F1D-ACBC-9CE11EE9A2A1") },
            { "20", new Guid("0B628DE4-07AD-4284-81CA-5B439F67C5E6") },
            { "20.1", new Guid("5370C727-1451-4700-A960-77630950AF6D") },
            { "21", new Guid("0D327DA6-B4DF-4842-B833-2CFF84F0948F") },
            { "22", new Guid("9AAF0EB6-42D8-46C1-A2EF-679511B37A0D") },
            { "23", new Guid("4AC6DFE1-607B-45B2-B289-D7FBCD44169C") },
            { "23.1", new Guid("D1DE6864-2236-48B7-99C3-D29C757903A4") },
            { "24.0", new Guid("8B4929F8-076F-4AEC-AFEE-8928747B7AE3") },
        };

        /// <summary>
        /// 通过guid找cad版本号
        /// </summary>
        /// <param name="clsid"></param>
        /// <returns>不存在返回null</returns>
        public static string GetAcadVer(string clsid)
        {
            return GetAcadVer(new Guid(clsid));
        }

        /// <summary>
        /// 通过guid找cad版本号
        /// </summary>
        /// <param name="clsid"></param>
        /// <returns>不存在返回null</returns>
        public static string GetAcadVer(Guid clsid)
        {
            return AcadClsIds.FirstOrDefault(q => q.Value == clsid).Key;
        }

        /// <summary>
        /// 通过cad版本号找guid
        /// </summary>
        /// <param name="cadVer"></param>
        /// <returns></returns>
        public static Guid GetAcadGuid(string cadVer)
        {
            AcadClsIds.TryGetValue(cadVer, out Guid value);
            return value;
        }
    }
#endif


/// <summary>
/// Linq Distinct 消重
/// </summary>
public class AcadClsIdInfoDistinct : IEqualityComparer<AcadClsIdInfo>
{
    public bool Equals(AcadClsIdInfo? a, AcadClsIdInfo? b)
    {
        if (b is null)
            return a is null;
        else if (a is null)
            return false;
        if (ReferenceEquals(a, b))// 同一对象
            return true;

        return a.Version == b.Version || a.Version == b.AcadProduct?.Version;
    }
    public int GetHashCode(AcadClsIdInfo obj)
    {
        return base.GetHashCode();
    }
}

public class AcadClsIdInfo
{
    /// <summary>
    /// Acad产品注册表信息
    /// </summary>
    public static List<AcadProductKey>? AcadProductKeys = AcadRegedit.AcadProductKeys;
    AcadProductKey? _AcadProduct;
    public AcadProductKey? AcadProduct
    {
        get
        {
            _AcadProduct ??= AcadProductKeys?.FirstOrDefault(a => a.Version == Version);
            return _AcadProduct;
        }
    }

    public double VerNumber
    {
        get
        {
            double.TryParse(Version, out double verdouble);
            return verdouble;
        }
    }
    string? _Version;
    public string? Version
    {
        get
        {
            if (_Version is null && AcadProductKeys is not null)
            {
                foreach (var item in AcadProductKeys)
                {
                    if (item.Guid == Guid)
                    {
                        _Version = item.Version;
                        break;
                    }
                }
            }
            return _Version;
            // return AcadClsId.GetAcadVer(Guid);
        }
    }
    public Guid Guid { get; }
    public object Com { get; }

    public AcadClsIdInfo(Guid acadClsId, object acadCom, AcadProductKey? acadProduct = null)
    {
        Guid = acadClsId;
        Com = acadCom;
        _AcadProduct = acadProduct;
    }
}

public class AcadClsIdHelper
{
    // 参考自 http://www.cadgj.com/?p=297
    [DllImport("ole32.dll", EntryPoint = "CreateBindCtx")]
    static extern int CreateBindCtx(int reserved, out IBindCtx ppbc);

    [DllImport("ole32.dll", EntryPoint = "GetRunningObjectTable")]
    static extern int GetRunningObjectTable(int reserved, out IRunningObjectTable prot);

    /// <summary>
    /// 遍历进程
    /// </summary>
    /// <param name="action">程序名,com接口</param>
    public static void GetAllInstances(Action<string, object> action)
    {
        int retVal = GetRunningObjectTable(0, out IRunningObjectTable rot);
        if (retVal == 0)
        {
            rot.EnumRunning(out IEnumMoniker enumMoniker);
            var moniker = new IMoniker[1];
            while (enumMoniker.Next(1, moniker, IntPtr.Zero) == 0)
            {
                CreateBindCtx(0, out IBindCtx bindCtx);
                moniker[0].GetDisplayName(bindCtx, null, out string displayName);
                rot.GetObject(moniker[0], out object comObj);
                if (comObj is null)
                    continue;
                action.Invoke(displayName, comObj);
            }
        }
    }


    /// <summary>
    /// 获取已经启动的CAD进程的com
    /// </summary>
    /// <param name="apps">返回已经存在的参数</param>
    /// <param name="acadClsId">指定版本</param>
    public static void GetActiveAcadCom(List<AcadClsIdInfo> apps, Guid? acadClsId = null)
    {
        List<Guid> guids = new();
        if (acadClsId is null)
        {
            var kes = AcadClsIdInfo.AcadProductKeys;
            if (kes is not null)
                guids.AddRange(kes.Select(a => a.Guid));
            // guids = AcadClsId.AcadClsIds.Values.ToList();
        }
        else
        {
            guids.Add(acadClsId.Value);
        }
        GetAllInstances((displayName, comObj) => {
#if DEBUG
            // 不启动cad的时候运行一次,看看有什么GUID,然后再启动一个cad对比就知道了
            Debug.WriteLine("****这个进程  " + displayName);
#endif
            var guid = ConversionGuid(displayName);
            if (guid is not null && guids.Contains(guid.Value))
            {
                // 17.1存在的时候17也会存在,所以会有两个obj被保存
                apps.Add(new AcadClsIdInfo(guid.Value, comObj, null));
            }
        });
    }

    /// <summary>
    /// 显示名称转为Guid
    /// </summary>
    /// <param name="displayName">显示名称 "!{6AB55F46-2523-4701-2222-B226F46252BA}"</param>
    /// <returns></returns>
    static Guid? ConversionGuid(string displayName)
    {
        if (string.IsNullOrEmpty(displayName))
            return null;
        Guid? guid = null;
        try
        {
            displayName = displayName.Substring(2, displayName.Length - 3);
            guid = new Guid(displayName);
        }
        catch { }
        return guid;
    }
}